package com.khalil.kkadmin.kb.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.khalil.kkadmin.common.util.JsonUtil;
import com.khalil.kkadmin.common.util.TreeUtil;
import com.khalil.kkadmin.infrastructure.BaseService;
import com.khalil.kkadmin.kb.domain.KbDocumentDir;
import com.khalil.kkadmin.kb.repository.KbDocumentDirRepository;
import com.khalil.kkadmin.kb.service.KbDocumentDirService;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;

@Service
public class KbDocumentDirServiceImpl extends BaseService<KbDocumentDirRepository, KbDocumentDir, Long> implements KbDocumentDirService {

    public static final String DRAG_TYPE_BEFORE = "before";
    public static final String DRAG_TYPE_AFTER = "after";
    public static final String DRAG_TYPE_INNER = "inner";
    public static final String TREE_PATH_SPLIT = ",";

    public KbDocumentDirServiceImpl(KbDocumentDirRepository repository) {
        super(repository);
    }

    @Override
    public KbDocumentDir create(String json) {
        KbDocumentDir documentDir = super.create(json);
        // 构建树路径
        Long parentId = documentDir.getParentId();
        if (parentId != null && parentId > 0) {
            KbDocumentDir parent = repository.findById(parentId).orElseThrow(RuntimeException::new);
            documentDir.setTreePath(parent.getTreePath() + TREE_PATH_SPLIT + documentDir.getId());
        } else {
            documentDir.setTreePath(String.valueOf(documentDir.getId()));
        }
        Integer maxOrderNum = repository.findMaxOrderNumByParentId(parentId);
        documentDir.setOrderNum(maxOrderNum == null ? 0 : maxOrderNum + 1);
        return repository.save(documentDir);
    }

    @Override
    public KbDocumentDir update(String json) {
        KbDocumentDir updateInput = JSONObject.parseObject(json, KbDocumentDir.class);
        KbDocumentDir documentDir = repository.findById(updateInput.getId()).orElseThrow(RuntimeException::new);
        // 更新名称
        documentDir.setName(updateInput.getName());
        return repository.save(documentDir);
    }

    @Override
    protected KbDocumentDir str2CreateEntity(String json) {
        return JsonUtil.parseJson2Object(json, KbDocumentDir.class);
    }

    @Override
    protected KbDocumentDir str2UpdateEntity(String json) {
        return JsonUtil.parseJson2Object(json, KbDocumentDir.class);
    }

    @Override
    public List<KbDocumentDir> getKbDocumentDirTree() {
        List<KbDocumentDir> dirList = findAll();
        TreeUtil.sortTree(dirList, Comparator.comparing(KbDocumentDir::getOrderNum));
        return TreeUtil.buildTree(dirList, (menu) -> menu.getParentId() == null || menu.getParentId() <= 0);
    }

    @Override
    public void dragMove(Long id, Long refId, String dropType) {
        KbDocumentDir documentDir = repository.findById(id).orElseThrow(RuntimeException::new);
        KbDocumentDir refDocumentDir = repository.findById(refId).orElseThrow(RuntimeException::new);
        if (DRAG_TYPE_BEFORE.equals(dropType)) {
            Long parentId = refDocumentDir.getParentId();
            documentDir.setParentId(parentId);
            String treePath = computeTreePathFromBrother(id, refDocumentDir);
            documentDir.setTreePath(treePath);
            documentDir.setOrderNum(refDocumentDir.getOrderNum());
            refDocumentDir.setOrderNum(refDocumentDir.getOrderNum() + 1);
            repository.save(documentDir);
            repository.save(refDocumentDir);
            // 更新排序
            Integer refOrderNum = refDocumentDir.getOrderNum();
            multiUpdateChildrenOrderNum(id, parentId, refOrderNum);
        } else if (DRAG_TYPE_AFTER.equals(dropType)) {
            Long parentId = refDocumentDir.getParentId();
            documentDir.setParentId(parentId);
            String treePath = computeTreePathFromBrother(id, refDocumentDir);
            documentDir.setTreePath(treePath);
            documentDir.setOrderNum(refDocumentDir.getOrderNum() + 1);
            repository.save(documentDir);
            // 更新排序
            Integer refOrderNum = refDocumentDir.getOrderNum();
            multiUpdateChildrenOrderNum(id, parentId, refOrderNum);
        } else if (DRAG_TYPE_INNER.equals(dropType)) {
            Long parentId = refDocumentDir.getId();
            documentDir.setParentId(parentId);
            documentDir.setTreePath(refDocumentDir.getTreePath() + TREE_PATH_SPLIT + id);
            Integer maxOrderNum = repository.findMaxOrderNumByParentId(parentId);
            documentDir.setOrderNum(maxOrderNum == null ? 0 : maxOrderNum + 1);
            repository.save(documentDir);
        } else {
            throw new RuntimeException("dropType参数错误");
        }
    }

    private void multiUpdateChildrenOrderNum(Long startId, Long parentId, Integer refOrderNum) {
        List<KbDocumentDir> dirList = repository.findByParentIdOrderByOrderNum(parentId);
        int orderNum = refOrderNum;
        boolean flag = false;
        for (KbDocumentDir dir : dirList) {
            if (dir.getId().equals(startId)) {
                flag = true;
            } else {
                if (flag) {
                    orderNum++;
                    repository.updateOrderNum(dir.getId(), orderNum);
                }
            }
        }
    }

    private String computeTreePathFromBrother(Long id, KbDocumentDir refDocumentDir) {
        String treePath = refDocumentDir.getTreePath();
        if (treePath.endsWith(TREE_PATH_SPLIT)) {
            treePath = treePath.substring(0, treePath.length() - 1);
        }
        String parentTreePath = treePath.substring(0, treePath.lastIndexOf(TREE_PATH_SPLIT) + 1);
        treePath = parentTreePath + id;
        return treePath;
    }

    @Override
    public List<KbDocumentDir> list(String params) {
        return List.of();
    }


}
